package com.example.forum.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

/*
    敏感词过滤器
 */
@Component
public class SensitiveFilter {
    private static final Logger logger= LoggerFactory.getLogger(SensitiveFilter.class);
    //替换符
    private static final String REPLACE="***";
    //敏感词前缀树
    private TireNode root=new TireNode();

    @PostConstruct
    private void init(){
        InputStream is =null;
        InputStreamReader isr=null;
        BufferedReader bf=null;
        try {
            //读取敏感词文件
            is = this.getClass().getClassLoader().getResourceAsStream("sensitive.txt");
            isr=new InputStreamReader(is);
            bf=new BufferedReader(isr);
            String line=null;
            while((line=bf.readLine())!=null){
                //将所有敏感词加入到前缀树中
                addKey(line.trim());
            }
        } catch (IOException e) {
            logger.error("读取文件失败:"+e.getMessage());
        }finally {
            if(bf!=null){
                try {
                    bf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(isr!=null){
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    //将一个字符串加到敏感词前缀树上
    private void addKey(String sensitive){
        TireNode temp=root;
        if(root.getMap().isEmpty()){    //树为空时
             //直接将词添加上去
             for(int i=0;i<sensitive.length();i++){
                if(i>0){
                    temp=temp.getMap().get(sensitive.charAt(i-1));
                }
                //创建一个节点
                TireNode tireNode=new TireNode();
                if(i==sensitive.length()-1){
                    //最后一个标记为敏感词结尾
                    tireNode.setKeyWordEnd(true);
                }
                //将子节点添加到父节点的map集合中
                temp.getMap().put(sensitive.charAt(i),tireNode);
             }
             return;
        }
        //树不为空时
        int i=0;
        //当树的n层有敏感词的第n-1个字符时，就一直向下寻找,找到不符合条件的位置
        while(isContainStart(temp,sensitive.charAt(i))){
            temp=temp.getMap().get(sensitive.charAt(i));
            i++;
        }
        while (i<sensitive.length()){
            //将敏感词剩下的字符加到树上
            TireNode tireNode=new TireNode();
            if(i==sensitive.length()-1){
                tireNode.setKeyWordEnd(true);
            }
            temp.getMap().put(sensitive.charAt(i),tireNode);
            temp=temp.getMap().get(sensitive.charAt(i));
            i++;
        }
    }

    //判断当前节点的map集合当中是否包含了该字符
    private boolean isContainStart(TireNode node,char c){
        if(node==null || node.getMap().isEmpty()){
            return false;
        }
        Map<Character,TireNode> map = node.getMap();
        Set<Character> characters = map.keySet();
        for(char ch:characters){
            if(ch==c){
                return true;
            }
        }
        return false;
    }

    //过滤文本中的敏感词
    public String filter(String text){
        StringBuilder stringBuilder=new StringBuilder("");
        int i=0,j=0;
        while (i<text.length()){
            TireNode temp=root;
            //如果当前字符不是敏感词的开头
            if(!temp.getMap().containsKey(text.charAt(i))){
                //将合法的字符记录下来
                stringBuilder.append(text.charAt(i));
                i++;
                j=i;
            }else if(temp.getMap().get(text.charAt(i)).isKeyWordEnd){   //当前字符是敏感词，并且是结尾
                stringBuilder.append(REPLACE);
                i++;
                j=i;
            }else{ //当前字符疑是敏感词组成部分
                boolean flag=true;
                while(flag && j<text.length() && i<text.length()){
                    temp=temp.getMap().get(text.charAt(j));
                    //判断是否与后面的字符组成敏感词
                    j++;
                    //没有与下一个字符组成敏感词
                    if(!temp.getMap().containsKey(text.charAt(j))){
                        //将合法字符记录下来
                        for(int k=i;k<=j;k++){
                            stringBuilder.append(text.charAt(k));
                        }
                        i++;
                        j=i;
                        flag=false;
                    }else if(temp.getMap().get(text.charAt(j)).isKeyWordEnd){   //与下一个字符组成敏感词
                        stringBuilder.append(REPLACE);
                        i=j+1;
                        j=i;
                        flag=false;
                    }
                }
            }
        }
        return stringBuilder.toString();
    }

    //遍历敏感词前缀树
    private void print(TireNode node){
        Map<Character, TireNode> map = node.getMap();
        Set<Character> keys = map.keySet();
        for(char key:keys){
            //输出当前父节点
            System.out.print(key+" ");
            //该节点还有子节点
            if(map.get(key)!=null){
                print(map.get(key));
            }
        }
    }
    private void print(){
        if(root.getMap().isEmpty()){
            System.out.println("没有添加敏感字");
            return;
        }
        print(root);
    }

    //前缀树节点
    private class TireNode{
        //该节点是否为叶子节点
        private boolean isKeyWordEnd=false;
        private Map<Character,TireNode> map=new HashMap<>();

        public boolean isKeyWordEnd() {
            return isKeyWordEnd;
        }

        public void setKeyWordEnd(boolean keyWordEnd) {
            isKeyWordEnd = keyWordEnd;
        }

        public Map<Character, TireNode> getMap() {
            return map;
        }

        public void setMap(Map<Character, TireNode> map) {
            this.map = map;
        }
    }

    public static void main(String[] args) {
        SensitiveFilter sensitiveFilter=new SensitiveFilter();
        sensitiveFilter.addKey("傻逼");
        sensitiveFilter.addKey("傻子");
        sensitiveFilter.addKey("废物");
        sensitiveFilter.addKey("超你妈");
//        String str = sensitiveFilter.filter("你是傻逼吗");
        String str = sensitiveFilter.filter("超你妈的，大傻逼傻子");
        System.out.println(str);
    }
}
